react hooksのみで快適flux生活
example
以下に書くstore.jsを用意する
main.jsで自分のApp コンポーネントを <Provider>でwrapする
コンポーネントの中ではこんな感じで使える
code:js
import useStore from './store'
function Hoge() {
function onClick(e) {
dispatch(addTodo(e.target.value));
}
return (
<>
{state.todos.map(text => <li>{text}</li>)}
<button onClick={onClick}> add </button>
/<>
)
}
こういう感じでstateを更新する関数addTodoを作ってdispatchに渡せば良くなる
その場ですぐに param => state => newstateな関数を作ればいい
必要なら別ファイルにまとめてimportして使い回す
これでどこからでも直ちにglobal stateを引っ張ってdispatchもできる
code:store.js
import React, { useReducer, useContext } from "react";
export const Store = React.createContext();
function reducer(prev, newState) {
//第2引数はuseStore使ってる側から渡されるもの
// 関数だったらprev渡して、そうじゃなかったらこれ自体が新しいstateの内容物というAPIにしている↓
const _newState = typeof newState === "function" ? newState(prev) : newState;
// もしreduxに設計を寄せたいなら、
// ここで第2引数が{type: "ADD_TODO", ...}のようなreduxにおけるアクションのobjectだったら、
//それごとの処理をする内容などを書いてもいいと思う
return {...prev, ..._newState};
};
export const Provider = ({ children, initialState }) => {
return (
);
};
export function useStore() {
return useContext(Store);
}
reducerのactionを関数も受けられるようにしている
reduxの場合
アクションオブジェクトをdispatchする
こんなの{type: "ADD_TODO" payload: {ここに何らかの引数的な情報} }
今回の場合
stateを変更したいのだから
「stateを引数として新しいstateを返す関数」を渡せばいい
payload的な情報を渡すことを考えると
payload => prevState => newStateみたいな形の関数を用意して部分適用みたいな風にするといい
関数じゃなくてオブジェクトを渡したら元のstateにマージされる
これはほとんどuseStateと同じAPI
ちなみにreducer内でオブジェクトのマージするようにするとactionを書くのが少し楽になる
keyを消したいときは面倒かもしれん
しかし普通stateのkeyは増減しないし良さそう
下階層も考慮したい
あとでやる
main.jsではこうやる
code:js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "./store";
import App from "./App";
const initialState = {
};
ReactDOM.render(
<Provider initialState={initialState}>
<App />
</Provider>,
document.querySelector("#app")
);
本当に一切reduxが不要になるかはまだわからない
しかし、最初の一歩としては良い気がする
あとからreduxに切り替えるのも大変には見えない
そもそもfluxという点で設計は同じなので
似た記事もあった
これはtypescriptでちゃんと型も入れてる
関係ないけどtypescriptでtsとtsx間違えるの注意